# [JS进阶]proto、prototype、继承三者的关系就这么简单
# 核心四句
- 1、所有对象都有__proto__属性来标识自己所继承的原型;
- 2、函数才有prototype属性;
- 3、创建函数时,JS会为这个函数自动添加prototype属性,值是一个有 constructor 属性的对象;
- 4、函数当作构造函数调用(通过new调用),JS会帮助创建构造函数的实例,实例通过设置自己的__proto__指向构造函数的prototype来实现继承;
# 实例解析
# 1、定义对象和函数
//字面量定义对象
let a = {};
//构造函数定义对象
let b = new Object();
//定义函数
function f(){};
//函数作为构造函数创建实例
let c = new f();
# 2、输出比较
在浏览器的控制台console中输入上述定义的对象和函数,进行_proto_和prototype的比较:
# 3、输出解析
# 1)所有对象都有__proto__属性来标识自己所继承的原型
比教上述所有输出的截图:无论对象还是函数,所有的输出都含有__proto__
,为什么函数也有__proto__
呢?因为函数本质上是特殊的对象
,所有函数也是有__proto__
的;从中可以验证所有对象都有__proto__属性来标识自己所继承的原型
。为了验证函数也是对象可以使用instanceof
进行判断:
Function instanceof Object // true
# 2)函数才有prototype属性
上图中,只有f
和Object
输出中才有prototype
,说明他们都是函数,对于f
我们很容易判断,因为在定义时就决定了它时函数的事实,但是Object
也是函数吗?不妨同样使用instanceof
进行判断:
Object instanceof Function // true
从结果我们可以得出:Object
底层定义为函数,我们通过new
关键字调用的时候,就将Object
作为构造函数使用的。
# 3)创建函数时,JS会为这个函数自动添加prototype属性,值是一个有 constructor 属性的对象
输出
函数f的prototype
,其实质是一个包含constructor属性的对象
;
# 4)函数当作构造函数调用(通过new调用),JS会帮助创建构造函数的实例,实例通过设置自己的__proto__指向构造函数的prototype来实现继承
这句话从本质上阐述了js中继承
的实现,即通过构造函数创建实例对象,实例的__proto__
其实指向其构造函数的prototye属性
;同样,我们用代码来验证下:
a.__proto__ === Object.prototype //true
b.__proto__ === Object.prototype //true
c.__proto__ === f.prototype //true
注意:字面量方式创建对象其底层也是通过
new Object
实现的,所有let a = {} 等价于 let a = new Object()
。
# 4、原型和继承图
上图为
原型链图
,我们对上图进行人为的分区处理,大致分为四个区域,我们不妨将上面的分析和核心四句
和原型链图
对应起来理解:
- 1、
Function instanceof Object // true
Object instanceof Function // true
(区域1
),当然到底是先有鸡还是先有蛋的探究这里就不深入了; - 2、对最底层
Object
继续进行原型跟踪,最终__proto__为null
(区域1
); - 3、定义的函数通过new关键字调用,生成新的函数实例的
__proto__继承了构造函数.prototype
(区域2
); - 4、函数的
prototype
属性的构造函数constructor
指向函数本身(区域1,2,3
)f === f.prototype.constructor //true Function === Object.prototype.constructor //true Object === Object.prototype.constructor
# 5、小结
在javascript中,通过__proto__和prototype的合作实现了原型链,以及对象的继承。另外,对于作为构造函数的函数而言,可以使用prototype存放要共享的属性和方法,也可以设置prototype指向现存的对象来继承该对象。 对于任何对象而言,其自身的__proto__指向自己构造函数的prototype属性,通过obj.proto.proto...一层一层的调用实现了原型链。其中包括操作符instanceof本质上是通过探测obj.proto.proto... 是否最终等于构造函数constructor.prototype来验证obj是否是构造函数constructor的实例。